#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
LimeReader macOS 完整构建脚本
从源码编译到.app包的完整流程

功能:
1. CMake构建
2. Qt依赖处理
3. .app包创建
4. DMG打包
5. OSS上传

作者: Wang Zhen
版本: 1.0.0
"""

import os
import sys
import json
import shutil
import subprocess
from pathlib import Path
from typing import Dict, Any, Optional
import logging

# 导入自定义模块
from create_macos_app import MacOSAppCreator
from create_macos_dmg import MacOSDMGCreator
from oss_manager import OSSManager

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('macos_build.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

class MacOSBuilder:
    """macOS完整构建器"""

    def __init__(self, config_file: str = 'release_config.json'):
        """
        初始化构建器

        Args:
            config_file: 配置文件路径
        """
        self.config_file = config_file
        self.config = self.load_config()
        self.project_root = Path(__file__).parent.parent
        self.build_dir = self.project_root / self.config['build_config']['build_dir']
        self.dist_dir = self.project_root / self.config['build_config']['dist_dir']

        # 初始化组件
        self.app_creator = MacOSAppCreator(config_file)
        self.dmg_creator = MacOSDMGCreator(config_file)
        self.oss_manager = OSSManager(config_file)

    def load_config(self) -> Dict[str, Any]:
        """加载配置文件"""
        try:
            with open(self.config_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except FileNotFoundError:
            logger.error(f"配置文件不存在: {self.config_file}")
            return self.get_default_config()
        except Exception as e:
            logger.error(f"配置文件加载失败: {e}")
            return self.get_default_config()

    def get_default_config(self) -> Dict[str, Any]:
        """获取默认配置"""
        return {
            "app_info": {
                "name": "LimeReader",
                "chinese_name": "影谷长图处理大师",
                "bundle_id": "com.limereader.desktop",
                "version": "1.0.0"
            },
            "build_config": {
                "build_dir": "build",
                "cmake_config": "Release",
                "parallel_jobs": 4
            }
        }

    def build_project(self, version: str, clean: bool = False) -> Dict[str, Any]:
        """
        构建项目

        Args:
            version: 版本号
            clean: 是否清理构建目录

        Returns:
            构建结果字典
        """
        logger.info(f"=== 开始构建项目 v{version} ===")

        try:
            # 1. 清理构建目录
            if clean and self.build_dir.exists():
                logger.info("清理构建目录")
                shutil.rmtree(self.build_dir)

            # 2. 创建构建目录
            self.build_dir.mkdir(exist_ok=True)
            build_config = self.config['build_config']['cmake_config']

            # 3. CMake配置
            logger.info("CMake配置...")
            cmake_cmd = [
                'cmake',
                str(self.project_root),
                f'-DCMAKE_BUILD_TYPE={build_config}',
                f'-DLongImageReader_VERSION={version}'
            ]

            if sys.platform == 'darwin':
                # macOS特定配置
                cmake_cmd.extend([
                    '-DCMAKE_OSX_DEPLOYMENT_TARGET=10.15',
                    '-DQt6_DIR=/opt/homebrew/opt/qt6/lib/cmake/Qt6'
                ])

            result = subprocess.run(cmake_cmd, cwd=self.build_dir, capture_output=True, text=True)

            if result.returncode != 0:
                return {
                    'success': False,
                    'error': f'CMake配置失败: {result.stderr}'
                }

            logger.info("CMake配置成功")

            # 4. 编译
            logger.info("开始编译...")
            parallel_jobs = self.config['build_config'].get('parallel_jobs', 4)
            build_cmd = ['cmake', '--build', '.', '--config', build_config]

            if parallel_jobs > 1:
                build_cmd.extend(['--parallel', str(parallel_jobs)])

            result = subprocess.run(build_cmd, cwd=self.build_dir, capture_output=True, text=True)

            if result.returncode != 0:
                return {
                    'success': False,
                    'error': f'编译失败: {result.stderr}'
                }

            logger.info("编译成功")

            # 5. 查找可执行文件
            executable_name = self.config['app_info']['name']
            executable_path = None

            # 在不同平台查找可执行文件
            possible_paths = [
                self.build_dir / "bin" / executable_name,
                self.build_dir / "Release" / executable_name,
                self.build_dir / executable_name
            ]

            for path in possible_paths:
                if path.exists():
                    executable_path = path
                    break

            if not executable_path:
                return {
                    'success': False,
                    'error': f'未找到可执行文件: {executable_name}'
                }

            logger.info(f"找到可执行文件: {executable_path}")

            return {
                'success': True,
                'executable_path': str(executable_path),
                'build_dir': str(self.build_dir),
                'message': '项目构建成功'
            }

        except Exception as e:
            error_msg = f"构建项目失败: {e}"
            logger.error(error_msg)
            return {
                'success': False,
                'error': error_msg
            }

    def create_app_package(self, executable_path: str, version: str) -> Dict[str, Any]:
        """
        创建.app包

        Args:
            executable_path: 可执行文件路径
            version: 版本号

        Returns:
            创建结果字典
        """
        logger.info("=== 创建.app包 ===")

        result = self.app_creator.create_app_bundle(Path(executable_path), version, self.dist_dir)

        if result['success']:
            logger.info(f".app包创建成功: {result['app_path']}")
        else:
            logger.error(f".app包创建失败: {result['error']}")

        return result

    def create_dmg_package(self, app_path: str, version: str) -> Dict[str, Any]:
        """
        创建DMG包

        Args:
            app_path: .app包路径
            version: 版本号

        Returns:
            创建结果字典
        """
        logger.info("=== 创建DMG包 ===")

        result = self.dmg_creator.create_dmg(Path(app_path), version, self.dist_dir)

        if result['success']:
            logger.info(f"DMG包创建成功: {result['dmg_path']}")
        else:
            logger.error(f"DMG包创建失败: {result['error']}")

        return result

    def upload_to_oss(self, file_path: str, remote_name: str) -> Dict[str, Any]:
        """
        上传文件到OSS

        Args:
            file_path: 本地文件路径
            remote_name: 远程文件名

        Returns:
            上传结果字典
        """
        logger.info("=== 上传到OSS ===")

        if not self.oss_manager.is_available():
            return {
                'success': False,
                'error': 'OSS不可用'
            }

        result = self.oss_manager.upload_file(Path(file_path), remote_name)

        if result['success']:
            logger.info(f"OSS上传成功: {remote_name}")
        else:
            logger.error(f"OSS上传失败: {result['error']}")

        return result

    def build_and_package(self, version: str, clean: bool = False, upload: bool = True) -> Dict[str, Any]:
        """
        完整的构建和打包流程

        Args:
            version: 版本号
            clean: 是否清理构建目录
            upload: 是否上传到OSS

        Returns:
            构建结果字典
        """
        logger.info(f"=== 开始完整构建流程 v{version} ===")

        results = {
            'version': version,
            'build': {},
            'app_package': {},
            'dmg_package': {},
            'oss_upload': {},
            'success': False
        }

        try:
            # 1. 构建项目
            build_result = self.build_project(version, clean)
            results['build'] = build_result

            if not build_result['success']:
                return results

            # 2. 创建.app包
            app_result = self.create_app_package(build_result['executable_path'], version)
            results['app_package'] = app_result

            if not app_result['success']:
                return results

            # 3. 创建DMG包
            dmg_result = self.create_dmg_package(app_result['app_path'], version)
            results['dmg_package'] = dmg_result

            if not dmg_result['success']:
                return results

            # 4. 上传到OSS
            if upload and self.oss_manager.is_available():
                # 上传DMG文件
                oss_result = self.upload_to_oss(dmg_result['dmg_path'], dmg_result['dmg_name'])
                results['oss_upload'] = oss_result

                if not oss_result['success']:
                    # OSS上传失败不是致命错误
                    logger.warning("OSS上传失败，但构建和打包成功")
            else:
                logger.info("跳过OSS上传")

            # 5. 生成构建报告
            self.generate_build_report(results, version)

            results['success'] = True
            logger.info("=== 完整构建流程完成 ===")

            return results

        except Exception as e:
            error_msg = f"构建流程失败: {e}"
            logger.error(error_msg)
            results['error'] = error_msg
            return results

    def generate_build_report(self, results: Dict[str, Any], version: str):
        """生成构建报告"""
        report = {
            'build_info': {
                'version': version,
                'build_date': datetime.now().isoformat(),
                'platform': 'macOS',
                'config': self.config['build_config']
            },
            'results': results,
            'success': results['success']
        }

        report_file = self.dist_dir / f'macos_build_report_v{version}.json'
        with open(report_file, 'w', encoding='utf-8') as f:
            json.dump(report, f, indent=2, ensure_ascii=False)

        logger.info(f"构建报告已生成: {report_file}")

def main():
    """主函数"""
    import argparse

    parser = argparse.ArgumentParser(description='LimeReader macOS完整构建工具')
    parser.add_argument('--config', default='release_config.json', help='配置文件路径')
    parser.add_argument('--version', required=True, help='版本号')
    parser.add_argument('--clean', action='store_true', help='清理构建目录')
    parser.add_argument('--skip-upload', action='store_true', help='跳过OSS上传')
    parser.add_argument('--build-only', action='store_true', help='只构建，不打包')
    parser.add_argument('--package-only', help='只打包指定的可执行文件')

    args = parser.parse_args()

    try:
        builder = MacOSBuilder(args.config)

        if args.build_only:
            # 只构建
            result = builder.build_project(args.version, args.clean)
        elif args.package_only:
            # 只打包
            executable_path = args.package_only
            app_result = builder.create_app_package(executable_path, args.version)
            if app_result['success']:
                dmg_result = builder.create_dmg_package(app_result['app_path'], args.version)
                if not args.skip_upload and builder.oss_manager.is_available():
                    builder.upload_to_oss(dmg_result['dmg_path'], dmg_result['dmg_name'])
            result = {'success': app_result['success'] and dmg_result['success']}
        else:
            # 完整流程
            result = builder.build_and_package(
                version=args.version,
                clean=args.clean,
                upload=not args.skip_upload
            )

        if result['success']:
            print("✅ macOS构建成功!")
            return 0
        else:
            print(f"❌ macOS构建失败: {result.get('error', '未知错误')}")
            return 1

    except Exception as e:
        print(f"❌ 执行失败: {e}")
        return 1

if __name__ == '__main__':
    sys.exit(main())